package jp.tkym.labs.swing3d;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Desktop.Action;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import jp.tkym.labs.geom.Vector3f;
import jp.tkym.labs.m3d.Camera3D;
import jp.tkym.labs.m3d.ColorM3D;
import jp.tkym.labs.m3d.DeviceTranslator;
import jp.tkym.labs.m3d.DrawableBinder;
import jp.tkym.labs.m3d.Line3D;
import jp.tkym.labs.m3d.Modeling3D;
import jp.tkym.labs.m3d.ModelingPoint3D;
import jp.tkym.labs.m3d.ProjectionTranslator;
import jp.tkym.labs.m3d.Rect3D;
import jp.tkym.labs.swing3d.drawer.DrawG2D;
import jp.tkym.labs.swing3d.drawer.ModelConverterForSwing;

/**
 * 
 * @author takayama
 */
public class DemoOnSwing2 {
	private DPanel panel = new DPanel();
	private Modeling3D modeling;
	private DrawableBinder<DrawG2D> binder;
	CanvasSwing canvas;
	private Timer timer;
	private boolean syncAspect = true;
	private boolean syncDevice = true;
	
	interface GwtAction{
		
	}
	
	DemoOnSwing2() {
		modeling = new Modeling3D();
		final Camera3D camera = modeling
				.on("v1")
				.moveOnY(-50.0f)
				.rotateBeta((float) (-Math.PI / 2))
				.camera(new DeviceTranslator(800, 600),
						ProjectionTranslator.createByRatio(
								(double) (4.0d / 3.0d), 800.0f / 600.0f));
		float len = 50.0f;

		Rect3D rect = new Rect3D(len, len);
		rect.setColor(new ColorM3D(255,255,255));
		ModelingPoint3D p0 = modeling.on("p0")
				.moveOnZ(-25.0f).moveOnX(-25.0f);
		new WireLine(len).draw(p0);
		p0.on("p2")
				.moveOnZ(50.0f)
				.add(rect)
				;
		
		canvas = new CanvasSwing(panel);
		panel.setPaintableLayer(canvas);
		binder = new DrawableBinder<DrawG2D>(canvas,
				new ModelConverterForSwing(), camera);
		
		binder.setBackground(new DrawG2D() {
		// draw background
			@Override
			public void draw(Graphics2D g2d) {
				g2d.setColor(Color.BLACK);
				g2d.fillRect(0, 0, g2d.getClipBounds().width,
						g2d.getClipBounds().height);
			}
		});
		
		// sync view size
		binder.addPropertyChangeListener(new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				if (evt.getPropertyName().equals(CanvasSwing.SIZE_PROPERTY)) {
					Object obj = evt.getNewValue();
					if (obj == null)
						return;
					if (!(obj instanceof Dimension))
						return;
					Dimension dim = (Dimension) obj;
					double asp = (double) ((double) dim.width / (double) dim.height);
					if (syncAspect)
						camera.getProjectionTranslator().setAspect(asp);
					if (syncDevice)
						camera.setDeviceTranslator(new DeviceTranslator(
								dim.width, dim.height));
					binder.sync();
				}
			}
		});
		
		binder.sync();
	}

	class WireLine{
		private float len;
		WireLine(float len) {
			this.len = len;
		}
		ModelingPoint3D draw(ModelingPoint3D model){
			for(int i=0; i<6; i++){
				model.add(new Line3D(new Vector3f(0.0f, 10.0f*i, 0.0f), new Vector3f(0.0f, 10.0f*i, len)));
				model.add(new Line3D(new Vector3f(10.0f*i, 0.0f, 0.0f), new Vector3f(10.0f*i, 0.0f, len)));
				model.add(new Line3D(new Vector3f(0.0f, 0.0f, 10.0f*i), new Vector3f(0.0f, len, 10.0f*i)));
				model.add(new Line3D(new Vector3f(10.0f*i, 0.0f, 0.0f), new Vector3f(10.0f*i, len, 0.0f)));
				model.add(new Line3D(new Vector3f(0.0f, 10.0f*i, 0.0f), new Vector3f(len, 10.0f*i, 0.0f)));
				model.add(new Line3D(new Vector3f(0.0f, 0.0f, 10.0f*i), new Vector3f(len, 0.0f, 10.0f*i)));
			}
			return model;
		}
	}
	
	ActionListener run = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			timer = new Timer(false);
			
			
			
			
			TimerTask task = new TimerTask() {
				@Override
				public void run() {
//					modeling.on("p0").moveOnY(1.0f);
					modeling.on("p0").rotateBeta((float)Math.PI/180);
					try {
						SwingUtilities.invokeAndWait(new Runnable() {
							@Override
							public void run() {
								binder.sync();
								canvas.repaint();
							}
						});
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			};
			timer.scheduleAtFixedRate(task, 1L, 10L);
		}
	};

	ActionListener stop = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (timer != null)
				timer.cancel();
			timer = null;
		}
	};

	/**
	 * Sample Component implementing Painting
	 * 
	 * @author kazunari
	 */
	@SuppressWarnings("serial")
	class DPanel extends JPanel {
		PaintableLayerComponent paintableLayer = null;

		public void setPaintableLayer(PaintableLayerComponent paintLayer) {
			paintableLayer = paintLayer;
		}

		@Override
		public void paint(Graphics g) {
			if (paintableLayer != null) {
				paintableLayer.setSize(this.getSize());
				paintableLayer.paintBefore(g);
			}
			super.paint(g);
			if (paintableLayer != null)
				paintableLayer.paintAfter(g);
		}
	}

	static JFrame createFrame() {
		DemoOnSwing2 demo = new DemoOnSwing2();
		// create sizeLabel
		final JLabel sizeLabel = new JLabel();
		PropertyChangeListener listener = new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				if(!evt.getPropertyName().equals(CanvasSwing.SIZE_PROPERTY)) 
					return;
				Dimension size = (Dimension) evt.getNewValue();
				if (size == null) return;
				sizeLabel.setText("[" + size.getWidth() + ", "
						+ size.getHeight() + "]");
			}
		};
		demo.canvas.addPropertyChangeListener(listener);

		// create southPanel
		JPanel south = new JPanel();
		south.setLayout(new FlowLayout());
		JButton run = new JButton("run");
		run.addActionListener(demo.run);
		JButton stop = new JButton("stop");
		stop.addActionListener(demo.stop);
		south.add(sizeLabel);
		south.add(run);
		south.add(stop);

		// create Frame
		JFrame f = new JFrame();
		f.getRootPane().setLayout(new BorderLayout());

		f.getRootPane().add(demo.panel, BorderLayout.CENTER);
		f.getRootPane().add(south, BorderLayout.SOUTH);
		return f;
	}

	public static void main(String[] args) {
		try {
			SwingUtilities.invokeAndWait(new Runnable() {
				public void run() {
					JFrame frame = createFrame();
					frame.setPreferredSize(new Dimension(800, 500));
					frame.pack();
					frame.toFront();
					frame.setVisible(true);
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				}
			});
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
